package com.yangyang.ralearn.server;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;

import com.yangyang.ralearn.common.entity.base.AbstractDomainPredicate;
import com.yangyang.ralearn.common.entity.base.BaseAction;
import com.yangyang.ralearn.common.exception.ErrorActionException;
import com.yangyang.ralearn.common.exception.ReachGoalException;
import com.yangyang.ralearn.common.parser.ProblemParser;
import com.yangyang.ralearn.net.frame.FrameDecoder;
import com.yangyang.ralearn.net.message.AbstractMessage;
import com.yangyang.ralearn.server.parser.ParseException;
import com.yangyang.ralearn.server.parser.PlanParser;
import com.yangyang.ralearn.util.ErrorCode;

public class ServerManager {

	private Map<Integer, JServerEnvironment> mapId2Environment;
	private Map<Integer, Map<Integer, JSimulator>> mapId2Simulator;
	private Map<Integer, Channel> mapId2Channel;

	private ServerManager() {
		mapId2Environment = new HashMap<Integer, JServerEnvironment>();
		mapId2Simulator = new HashMap<Integer, Map<Integer, JSimulator>>();
		mapId2Channel = new HashMap<Integer, Channel>();
	}

	private static ServerManager instance;

	public static ServerManager instance() {
		if (instance == null)
			instance = new ServerManager();
		return instance;
	}

	public void addEnvironment(int key) {

	}

	public void removeChannel(int id) {
		this.mapId2Channel.remove(id);
		this.mapId2Environment.remove(id);
		this.mapId2Simulator.remove(id);
	}

	/**
	 * 
	 * @param groupId
	 * @param simulatorId
	 * @param problemFile
	 */
	public void addSimulator(int groupId, int simulatorId, String problemFile) {
		if (simulatorId <= 0 || problemFile == null)
			return;
		Map<Integer, JSimulator> map = this.mapId2Simulator.get(groupId);
		if (map == null) {
			map = new HashMap<Integer, JSimulator>();
			this.mapId2Simulator.put(groupId, map);
		}
		JSimulator simulator = map.get(simulatorId);
		if (simulator == null) {
			simulator = JSimulator.newInstance(groupId);
			map.put(simulatorId, simulator);
		}
		if (problemFile != null && !problemFile.isEmpty())
			try {
				ProblemParser problemParser = new ProblemParser(
						new FileInputStream(problemFile));
				problemParser.problem_def(simulator);
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				// return ErrorCode.ERR_COMMON.code();
			} catch (com.yangyang.ralearn.common.parser.ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				// return ErrorCode.ERR_COMMON.code();
			}
	}

	/**
	 * 添加一个新的环境组
	 * 
	 * @param groupId
	 * @param domainFile
	 * @param problemFile
	 * @return
	 */
	public int newGroup(int groupId, String domainFile, int simulatorId,
			String problemFile, Channel channel) {
		Logger.getLogger(ServerManager.class).info(
				"domain:" + domainFile + ",problem:" + problemFile);
		PlanParser domainParser = null;
		if (!this.mapId2Environment.containsKey(groupId)) {
			JServerEnvironment environment = JServerEnvironment
					.newInstance(groupId);
			JSimulator simulator = JSimulator.newInstance(groupId);
			this.mapId2Environment.put(groupId, environment);
			try {
				domainParser = new PlanParser(new FileInputStream(domainFile));
				domainParser.domain_def(environment);
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return ErrorCode.ERR_COMMON.code();
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return ErrorCode.ERR_COMMON.code();
			}
			environment.print();
			Logger.getLogger(ServerManager.class).debug(simulator);
		}
		this.addSimulator(groupId, simulatorId, problemFile);
		if (channel != null) {
			this.mapId2Channel.put(groupId, channel);
		}
		Logger.getLogger(ServerManager.class).debug("input action");
		return groupId;
	}

	public int nextProblem(int groupId, int simulatorId, String problemFile) {
		try {
			ProblemParser problemParser = new ProblemParser(
					new FileInputStream(problemFile));
			this.addSimulator(groupId, simulatorId, problemFile);
			problemParser.problem_def(ServerManager.instance()
					.getSimulatorById(groupId, simulatorId));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return ErrorCode.ERR_COMMON.code();
		} catch (com.yangyang.ralearn.common.parser.ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return ErrorCode.ERR_COMMON.code();
		}
		return 0;
	}

	public boolean canDo(int groupId, int simulatorId, BaseAction action) {
		return this.getSimulatorById(groupId, simulatorId).canDo(action);
	}

	public boolean doAction(int groupId, int simulatorId, BaseAction action) {
		try {
			this.getSimulatorById(groupId, simulatorId).doAction(action);
		} catch (ReachGoalException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ErrorActionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
		return true;

	}

	public List<AbstractDomainPredicate> observation(int groupId,
			int simulatorId) {
		return this.getSimulatorById(groupId, simulatorId).observe();
	}

	public JServerEnvironment getEnvironmentById(int groupId) {
		return this.mapId2Environment.get(groupId);
	}

	public JSimulator getSimulatorById(int groupId, int simulatorId) {
		return this.mapId2Simulator.get(groupId).get(simulatorId);
	}

	public void sendMessage(int groupId, AbstractMessage message,
			Integer... writable) {
		Channel channel = this.mapId2Channel.get(groupId);
		if (channel != null) {
			ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
			FrameDecoder.encode(buffer, message, writable);
			channel.write(buffer);
			// buffer.discardReadBytes();
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// ServerManager.instance().run();
	}

}
